package core

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	. "xrt/constants"
	. "xrt/interfaces"
	"xrt/utils/file/log"
	r "xrt/utils/reflect"
)

type NoSql struct {
	Kv  IfNoSqlKv
	Doc IfNoSqlDoc
}

type XRT struct {
	debug     bool
	staticPkg bool
	Sql       IfSql   //Sql操作接口
	NoSql     NoSql   //NoSql操作接口
	sync      IfSync  //同步服务接口
	async     IfAsync //异步服务接口
	//路由实例
	routeSync  map[string]interface{} //同步对象列表
	routeAsync map[string]interface{} //异步对象列表
	//Services实例
	servicesMap map[string]map[string]func(...interface{}) interface{} //Services映射[空间名:[Service名:方法体]]
	//注册路由
	registerSyncMap  map[string]interface{} //注册同步映射列表
	registerAsyncMap map[string]interface{} //注册异步映射列表
	//注册组件
	syncComponents     map[string]interface{} //同步对象组件列表
	asyncComponents    map[string]interface{} //异步对象组件列表
	sqlComponents      map[string]interface{} //Sql对象组件列表
	noSqlKvComponents  map[string]interface{} //Kv类型NoSql对象组件列表
	noSqlDocComponents map[string]interface{} //Doc类型NoSql对象组件列表
	//组件参数
	componentsParams map[string]map[string]string
}

//初始化
func (xrt *XRT) Initial(debug bool, multiCpu bool, logPath string, logLevel string, staticPkg bool, configs map[string]map[string]string) {
	//设置调试模式
	xrt.debug = debug
	//设置是否静态文件打包
	xrt.staticPkg = staticPkg
	//保留配置参数
	xrt.componentsParams = configs
	//启用多核处理
	if multiCpu {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}
	//初始化日志
	log.NewLogger(logPath, logLevel)
	//实例化工具型组件
	xrt.componentsInstants(CompSql, configs)
	xrt.componentsInstants(CompNoSqlKv, configs)
	xrt.componentsInstants(CompNoSqlKv, configs)
	//实例同步化路由
	xrt.syncRoutesInstants()
	//实例化异步路由
	xrt.asyncRoutesInstants()
	//实例化应用型组件
	xrt.componentsInstants(CompAsync, configs) //首先实例化异步组件
	xrt.componentsInstants(CompSync, configs)
}

//组件实例化方法
func (xrt *XRT) componentsInstants(key string, configs map[string]map[string]string) {
	if value, ok := configs["components"][key]; ok {
		switch key {
		case CompSync:
			if _, ok := xrt.syncComponents[value]; ok {
				xrt.sync = r.New(xrt.syncComponents[value]).(IfSync)
				xrt.sync.Initial(configs[value], xrt.routeSync)
			} else {
				panic(fmt.Sprintf("SyncComponents not Contains [%s].", value))
			}
		case CompAsync:
			if _, ok := xrt.asyncComponents[value]; ok {
				xrt.async = r.New(xrt.asyncComponents[value]).(IfAsync)
				xrt.async.Initial(configs[value], xrt.routeAsync)
			} else {
				panic(fmt.Sprintf("AsyncComponents not Contains [%s].", value))
			}
		case CompSql:
			if _, ok := xrt.sqlComponents[value]; ok {
				xrt.Sql = r.New(xrt.sqlComponents[value]).(IfSql)
				xrt.Sql.Connect(configs[value])
			} else {
				panic(fmt.Sprintf("SqlComponents not Contains [%s].", value))
			}
		case CompNoSqlKv:
			if _, ok := xrt.noSqlKvComponents[value]; ok {
				xrt.NoSql.Kv = r.New(xrt.noSqlKvComponents[value]).(IfNoSqlKv)
				xrt.NoSql.Kv.Connect(configs[value])
			} else {
				panic(fmt.Sprintf("NoSqlKvComponents not Contains [%s].", value))
			}
		case CompNoSqlDoc:
			if _, ok := xrt.noSqlDocComponents[value]; ok {
				xrt.NoSql.Doc = r.New(xrt.noSqlDocComponents[value]).(IfNoSqlDoc)
				xrt.NoSql.Doc.Connect(configs[value])
			} else {
				panic(fmt.Sprintf("NoSqlDocComponents not Contains [%s].", value))
			}
		default:
			panic(fmt.Sprintf("Not Support Component Type [%s].", value))
		}
	}
}

//同步路由实例化
func (xrt *XRT) syncRoutesInstants() {
	//实例化同步路由
	for sign, instance := range xrt.registerSyncMap {
		tempRoute := r.New(instance)
		mutRoute := reflect.ValueOf(tempRoute).Elem()

		//为路由及Service设置数据访问句柄
		if xrt.Sql != nil {
			mutRoute.FieldByName("Sql").Set(reflect.ValueOf(xrt.Sql))
		}
		if xrt.NoSql.Kv != nil || xrt.NoSql.Doc != nil {
			mutRoute.FieldByName("NoSql").Set(reflect.ValueOf(xrt.NoSql))
		}
		//为路由设置Service
		mutRoute.FieldByName("Services").Set(
			reflect.ValueOf(Service{Sql: xrt.Sql, NoSql: xrt.NoSql, nameSpace: sign}))

		xrt.routeSync[sign] = tempRoute
	}
}

//异步路由实例化
func (xrt *XRT) asyncRoutesInstants() {
	//实例化异步路由
	for sign, instance := range xrt.registerAsyncMap {
		tempRoute := r.New(instance)
		mutRoute := reflect.ValueOf(tempRoute).Elem()

		//为路由设置数据访问句柄
		if xrt.Sql != nil {
			mutRoute.FieldByName("Sql").Set(reflect.ValueOf(xrt.Sql))
		}
		if xrt.NoSql.Kv != nil || xrt.NoSql.Doc != nil {
			mutRoute.FieldByName("NoSql").Set(reflect.ValueOf(xrt.NoSql))
		}
		//为路由设置Service
		mutRoute.FieldByName("Services").Set(
			reflect.ValueOf(Service{Sql: xrt.Sql, NoSql: xrt.NoSql, nameSpace: sign}))

		xrt.routeAsync[sign] = tempRoute
	}
}

//注册同步服务
func (xrt *XRT) RegisterRoutesSync(rts ...interface{}) {
	for _, rt := range rts {
		rType := reflect.TypeOf(rt)
		routePath := fmt.Sprintf("%s/%s/%s", rType.PkgPath(), strings.Split(r.GetFileName(), ".")[0], rType.Name())
		//如果是组件内注册的内容直接从根目录开始
		if strings.HasPrefix(routePath, "xrt/components") {
			routePath = fmt.Sprintf("/%s/%s", strings.Split(r.GetFileName(), ".")[0], rType.Name())
		} else {
			routePath = strings.SplitN(routePath, AppHead, 2)[1]
			fmt.Printf("Register RouteSync \t[%s]\n", routePath)
		}
		xrt.registerSyncMap[routePath] = rt
	}
}

//注册异步服务
func (xrt *XRT) RegisterRoutesAsync(rtaS ...interface{}) {
	for _, rta := range rtaS {
		rType := reflect.TypeOf(rta)
		routePath := fmt.Sprintf("%s/%s/%s", rType.PkgPath(), strings.Split(r.GetFileName(), ".")[0], rType.Name())
		routePath = strings.SplitN(routePath, AppHead, 2)[1]
		fmt.Printf("Register RouteAsync \t[%s]\n", routePath)
		xrt.registerAsyncMap[routePath] = rta
	}
}

func checkService(se interface{}) (string, string) {
	sType := reflect.TypeOf(se)
	fileName := strings.Split(r.GetFileName(3), ".")[0]
	sName := sType.Name()
	if strings.HasSuffix(fileName, "_services") {
		fileName = string(fileName[0 : len(fileName)-9])
	} else {
		panic("Services File must be endsWith [_services].")
	}
	if strings.HasSuffix(sName, "Service") {
		sName = string(sName[0 : len(sName)-7])
	} else {
		panic("Service Structure must be endsWith [Service].")
	}
	nameSpace := fmt.Sprintf("%s/%s/%s", sType.PkgPath(), fileName, sName)
	nameSpace = strings.SplitN(nameSpace, AppHead, 2)[1]
	servicePath := fmt.Sprintf("%s/%s/%s", sType.PkgPath(), fileName+"_services", sName+"Service")
	servicePath = strings.SplitN(servicePath, AppHead, 2)[1]
	return nameSpace, servicePath
}

//注册Services
func (xrt *XRT) RegisterServices(ses ...interface{}) {
	for _, se := range ses {
		nameSpace, servicePath := checkService(se)
		if _, ok := xrt.registerSyncMap[nameSpace]; ok {
			xrt.servicesMap[nameSpace] = map[string]func(...interface{}) interface{}{}
			//注册Services到命名空间下
			muxTyp := reflect.TypeOf(se)
			muxVal := reflect.ValueOf(se)
			for i := 0; i < muxTyp.NumMethod(); i++ {
				muxTypMethod := muxTyp.Method(i)
				muxValMethod := muxVal.Method(i)
				xrt.servicesMap[nameSpace][muxTypMethod.Name] = muxValMethod.Interface().(func(...interface{}) interface{})
			}
			fmt.Printf("Register Services \t[%s] For NameSpace [%s]\n", servicePath, nameSpace)
		} else {
			fmt.Printf("UnBind Services \t[%s], Ignore It.\n", servicePath)
		}
	}
}

//注册组件
func (xrt *XRT) RegisterComponent(cType string, item interface{}) bool {
	componentSign := r.GetPkgName(item)
	if IsDebug() {
		fmt.Printf("Register\t[%s]\tComponent\t[%s]\n", cType, componentSign)
	}
	switch cType {
	case ImplSync:
		xrt.syncComponents[componentSign] = item
	case ImplAsync:
		xrt.asyncComponents[componentSign] = item
	case ImplSql:
		xrt.sqlComponents[componentSign] = item
	case ImplNoSqlKv:
		xrt.noSqlKvComponents[componentSign] = item
	case ImplNoSqlDoc:
		xrt.noSqlDocComponents[componentSign] = item
	default:
		panic("Register Unknown Interface. ")
	}
	return true
}

//返回Kv对象
func (xrt *XRT) GetKvInstants() IfNoSqlKv {
	return xrt.NoSql.Kv
}

//返回同步对象
func (xrt *XRT) GetSyncInstants() IfSync {
	return xrt.sync
}

//返回异步对象
func (xrt *XRT) GetAsyncInstants() IfAsync {
	return xrt.async
}

//返回对应组件的配置参数
func (xrt *XRT) GetComponentParams(compType string) map[string]string {
	componentMap := xrt.componentsParams["components"]
	if configTarget, ok := componentMap[compType]; ok {
		return xrt.componentsParams[configTarget]
	} else {
		log.Errorf("Get Component Type [%s], parameters not exists.", compType)
	}
	return nil
}

func (xrt *XRT) StartServe() {
	//是否配置了异步组件
	if xrt.async != nil {
		go xrt.async.Listening()
	}
	//启动同步组件监听
	xrt.sync.Listening()
}

//是否调试模式
func IsDebug() bool {
	return X.debug
}

//是否静态文件打包
func IsPkg() bool {
	return X.staticPkg
}

var X XRT

//初始化XRT
func init() {
	X = XRT{
		debug:              false,
		staticPkg:          false,
		NoSql:              NoSql{},
		routeSync:          map[string]interface{}{},
		routeAsync:         map[string]interface{}{},
		registerSyncMap:    map[string]interface{}{},
		registerAsyncMap:   map[string]interface{}{},
		syncComponents:     map[string]interface{}{},
		asyncComponents:    map[string]interface{}{},
		sqlComponents:      map[string]interface{}{},
		noSqlKvComponents:  map[string]interface{}{},
		noSqlDocComponents: map[string]interface{}{},
		servicesMap:        map[string]map[string]func(...interface{}) interface{}{},
	}
}
